001    /*
002     * Copyright 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library.info;
020    
021    import java.io.OutputStream;
022    import java.io.IOException;
023    import java.io.Writer;
024    import java.io.OutputStreamWriter;
025    import java.util.Properties;
026    
027    import net.dpml.lang.Category;
028    import net.dpml.lang.Version;
029    
030    import net.dpml.library.info.IncludeDirective.Mode;
031    
032    
033    /**
034     * Utility class used for construction of a module model from an XML source.
035     *
036     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
037     * @version 1.1.0
038     */
039    public final class LibraryEncoder extends LibraryConstants
040    {
041       /**
042        * Write a module directive to an output stream as a portable XML definition.
043        * During export dependencies are limited to runtime concerns (eliminating 
044        * build and test scoped dependencies).  Artifact production is strippped down
045        * to a generic type declaration.  The resulting XML file is suitable for 
046        * publication and usage by external projects.
047        *
048        * @param module the module directive to externalize
049        * @param output the output stream
050        * @exception IOException if an error occurs during module externalization
051        */
052        public void export( final ModuleDirective module, final OutputStream output ) throws IOException
053        {
054            final Writer writer = new OutputStreamWriter( output );
055            try
056            {
057                writer.write( XML_HEADER );
058                writer.write( "\n" );
059                
060                String name = module.getName();
061                String version = module.getVersion();
062                
063                if( null != name )
064                {
065                    writer.write( "<module name=\"" + name + "\"" );
066                }
067                if( null != version )
068                {
069                    writer.write( " version=\"" + version + "\"" );
070                }
071                
072                writer.write( 
073                  "\n    xmlns=\"" 
074                  + MODULE_XSD_URI
075                  + "\">" );
076                
077                String basedir = module.getBasedir();
078                InfoDirective info = module.getInfoDirective();
079                Properties properties = module.getProperties();
080                TypeDirective[] types = module.getTypeDirectives();
081                DependencyDirective[] dependencies = module.getDependencyDirectives();
082                ResourceDirective[] resources = module.getResourceDirectives();
083                
084                if( !info.isNull() )
085                {
086                    writer.write( "\n" );
087                    writeInfo( writer, info, "  " );
088                }
089                if( properties.size() > 0 )
090                {
091                    writer.write( "\n" );
092                    writeProperties( writer, properties, "  ", true );
093                }
094                if( types.length > 0 )
095                {
096                    writer.write( "\n" );
097                    writeTypes( writer, types, "  " );
098                }
099                if( dependencies.length > 0 )
100                {
101                    writer.write( "\n" );
102                    writeDependencies( writer, dependencies, "  " );
103                }
104                if( resources.length > 0 )
105                {
106                    writeResources( writer, resources, "  " );
107                }
108                writer.write( "\n\n</module>" );
109                writer.write( "\n" );
110            }
111            finally
112            {
113                writer.flush();
114                writer.close();
115            }
116        }
117        
118        private void writeModule( Writer writer, ModuleDirective module, String lead ) throws IOException
119        {
120            String name = module.getName();
121            String version = module.getVersion();
122            
123            InfoDirective info = module.getInfoDirective();
124            Properties properties = module.getProperties();
125            String basedir = module.getBasedir();
126            TypeDirective[] types = module.getTypeDirectives();
127            DependencyDirective[] dependencies = module.getDependencyDirectives();
128            ResourceDirective[] resources = module.getResourceDirectives();
129            
130            writer.write( "\n" + lead + "<module" );
131            if( null != name )
132            {
133                writer.write( " name=\"" + name + "\"" );
134            }
135            if( null != version )
136            {
137                writer.write( " version=\"" + version + "\"" );
138            }
139            writer.write( ">" );
140            
141            if( !info.isNull() )
142            {
143                writer.write( "\n" );
144                writeInfo( writer, info, lead + "  " );
145            }
146            if( properties.size() > 0 )
147            {
148                writer.write( "\n" );
149                writeProperties( writer, properties, lead + "  ", true );
150            }
151    
152            if( types.length > 0 )
153            {
154                writer.write( "\n" );
155                writeTypes( writer, types, lead + "  " );
156            }
157            
158            if( dependencies.length > 0 )
159            {
160                writer.write( "\n" );
161                writeDependencies( writer, dependencies, lead + "  " );
162            }
163            
164            if( resources.length > 0 )
165            {
166                writeResources( writer, resources, lead + "  " );
167            }
168            writer.write( "\n\n" + lead + "</module>" );
169        }
170        
171        private void writeResource( Writer writer, ResourceDirective resource, String lead ) throws IOException
172        {
173            String name = resource.getName();
174            String version = resource.getVersion();
175            
176            InfoDirective info = resource.getInfoDirective();
177            Properties properties = resource.getProperties();
178            String basedir = resource.getBasedir();
179            TypeDirective[] types = resource.getTypeDirectives();
180            DependencyDirective[] dependencies = resource.getDependencyDirectives();
181            
182            writer.write( "\n" + lead + "<resource"  );
183            if( null != name )
184            {
185                writer.write( " name=\"" + name + "\"" );
186            }
187            if( null != version )
188            {
189                writer.write( " version=\"" + version + "\"" );
190            }
191            writer.write( ">" );
192            
193            if( !info.isNull() )
194            {
195                writer.write( "\n" );
196                writeInfo( writer, info, lead + "  " );
197            }
198            if( properties.size() > 0 )
199            {
200                writeProperties( writer, properties, lead + "  ", true );
201            }
202            if( types.length > 0 )
203            {
204                writeTypes( writer, types, lead + "  " );
205            }
206            if( dependencies.length > 0 )
207            {
208                writeDependencies( writer, dependencies, lead + "  " );
209            }
210            writer.write( "\n" + lead + "</resource>" );
211        }
212        
213        private void writeInfo( 
214          Writer writer, InfoDirective info, String lead ) throws IOException
215        {
216            writer.write( lead + "<info" );
217            if( null != info.getTitle() )
218            {
219                writer.write( " title=\"" + info.getTitle() + "\"" );
220            }
221            String description = info.getDescription();
222            if( null != description )
223            {
224                writer.write( ">" );
225                writer.write( "\n" + lead + "  <description>" );
226                writer.write( "\n" + lead + "  " + description );
227                writer.write( "\n" + lead + "  </description>" );
228                writer.write( "\n" + lead + "</info>" );
229            }
230            else
231            {
232                writer.write( "/>" );
233            }
234        }
235        
236        private void writeProperties( 
237          Writer writer, Properties properties, String lead, boolean flag ) throws IOException
238        {
239            if( properties.size() > 0 )
240            {
241                if( flag )
242                {
243                    writer.write( "\n" + lead + "<properties>" );
244                }
245                String[] names = (String[]) properties.keySet().toArray( new String[0] );
246                for( int i=0; i<names.length; i++ )
247                {
248                    String name = names[i];
249                    String value = properties.getProperty( name );
250                    writer.write( "\n" + lead );
251                    if( flag )
252                    {
253                        writer.write( "  " );
254                    }
255                    writer.write( "<property name=\"" + name + "\" value=\"" + value + "\"/>" );
256                }
257                if( flag )
258                {
259                    writer.write( "\n" + lead + "</properties>" );
260                }
261            }
262        }
263        
264        private void writeTypes( Writer writer, TypeDirective[] types, String lead ) throws IOException
265        {
266            if( types.length > 0 )
267            {
268                writer.write( "\n" + lead + "<types>" );
269                for( int i=0; i<types.length; i++ )
270                {
271                    TypeDirective type = types[i];
272                    writeType( writer, type, lead + "  " );
273                }
274                writer.write( "\n" + lead + "</types>" );
275            }
276        }
277        
278        private void writeType( Writer writer, TypeDirective type, String lead ) throws IOException
279        {
280            String id = type.getID();
281            writer.write( "\n" + lead + "<type id=\"" + id + "\"" );
282            Version version = type.getVersion();
283            if( null != version )
284            {
285                if( Version.NULL_VERSION.equals( version ) )
286                {
287                    writer.write( " alias=\"true\"" );
288                }
289                else
290                {
291                    writer.write( " version=\"" + version.getMajor() + "." + version.getMinor() + "\"" );
292                }
293            }
294            writer.write( "/>" );
295        }
296        
297        private void writeDependencies( 
298          Writer writer, DependencyDirective[] dependencies, String lead ) throws IOException
299        {
300            if( dependencies.length > 0 )
301            {
302                writer.write( "\n" + lead + "<dependencies>" );
303            
304                for( int i=0; i<dependencies.length; i++ )
305                {
306                    DependencyDirective dependency = dependencies[i];
307                    IncludeDirective[] includes = dependency.getIncludeDirectives();
308                    if( includes.length > 0 )
309                    {
310                        Scope scope = dependency.getScope();
311                        String label = scope.toString().toLowerCase();
312                        writer.write( "\n" + lead + "  <" + label + ">" );
313                        for( int j=0; j<includes.length; j++ )
314                        {
315                            IncludeDirective include = includes[j];
316                            Mode mode = include.getMode();
317                            String value = include.getValue();
318                            writer.write( "\n" + lead + "    <include" );
319                            if( Mode.KEY.equals( mode ) )
320                            {
321                                writer.write( " key=\"" + value + "\"" );
322                            }
323                            else if( Mode.REF.equals( mode ) )
324                            {
325                                writer.write( " ref=\"" + value + "\"" );
326                            }
327                            else if( Mode.URI.equals( mode ) )
328                            {
329                                writer.write( " uri=\"" + value + "\"" );
330                            }
331                            
332                            if( Scope.RUNTIME.equals( scope ) )
333                            {
334                                Category category = include.getCategory();
335                                if( !Category.PRIVATE.equals( category ) )
336                                {
337                                    String name = category.getName().toLowerCase();
338                                    writer.write( " tag=\"" + name + "\"" );
339                                }
340                            }
341                            
342                            Properties props = include.getProperties();
343                            if( props.size() > 0 )
344                            {
345                                writer.write( ">" );
346                                writeProperties( writer, props, lead + "    ", false );
347                                writer.write( "\n" + lead + "    </include>" );
348                            }
349                            else
350                            {
351                                writer.write( "/>" );
352                            }
353                        }
354                        writer.write( "\n" + lead + "  </" + label + ">" );
355                    }
356                }
357                writer.write( "\n" + lead + "</dependencies>" );
358            }
359        }
360        
361        private void writeResources( Writer writer, ResourceDirective[] resources, String lead ) throws IOException
362        {
363            for( int i=0; i<resources.length; i++ )
364            {
365                ResourceDirective resource = resources[i];
366                if( resource instanceof ModuleDirective )
367                {
368                    writer.write( "\n" );
369                    ModuleDirective module = (ModuleDirective) resource;
370                    writeModule( writer, module, lead );
371                }
372                else
373                {
374                    writer.write( "\n" );
375                    writeResource( writer, resource, lead );
376                }
377            }
378        }
379    }